const t = require('@babel/types');
const traverse = require('@babel/traverse').default;
const types = require('@babel/types');
const parser = require("@babel/parser");
const generate = require('@babel/generator').default;
const {get_file,get_rand_names} = require("../tools/utils")

/*
从 string 生成一个ast对象
 */
function getAstByString(code){
    // console.log(code);
    var ast = parser.parse(code, { sourceType: 'module' });
    return ast;
}

/*
从文件中生成一个ast对象
 */
function getAstByFile(file_name){
    var code = get_file(file_name);
    return getAstByString(code);
}

/*
将一个ast对象生成为code string
 */
function genCodeByAst(ast){
    var output = generate(ast, {});
    return output.code;
}

/*
对cache的参数进行重命名
 */
function renameAllCacheParam(ast, names, repeatedCacheParam){
    traverse(ast,{
        CatchClause(path){
            if(path.node.param){
                if(repeatedCacheParam.has(path.node.param.name)){
                    path.scope.rename(path.node.param.name, names.pop());
                }
            }
        }
    })
}

/*
对函数参数全部重命名
 */
function renameAllFuncParam(ast, names, repeated_func) {
    traverse(ast, {
        // 捕获函数表达式
        FunctionExpression(path) {
            renameParams(path, names, repeated_func);
        },
        // 捕获函数声明
        FunctionDeclaration(path) {
            renameParams(path, names, repeated_func);
        },
        // 捕获箭头函数表达式
        ArrowFunctionExpression(path) {
            renameParams(path, names, repeated_func);
        }
    });
}

function renameParams(path, names, repeated_func) {
    if (path.node.params) {
        for (let i = 0; i < path.node.params.length; i++) {
            const nodei = path.node.params[i];
            // 确保参数是 Identifier 类型
            if (types.isIdentifier(nodei) && repeated_func.has(nodei.name)) {
                path.scope.rename(nodei.name, names.pop());
            }
        }
    }
}


/*
对函数名全部重命名
 */
function renameAllFuncName(ast, names, repeated_func){
    traverse(ast,{
        FunctionDeclaration(path){
            if(path.node.id&&repeated_func.has(path.node.id.name)){
                path.scope.rename(path.node.id.name, names.pop());
            }
        },
        VariableDeclarator(path){
            if(path.node.id&&path.node.init&&path.node.init.type==="FunctionExpression"){
                if(path.node.id&&repeated_func.has(path.node.id.name)){
                    path.scope.rename(path.node.id.name, names.pop());
                }
            }
        },
    })
}

/*
一次性对所有的变量进行重命名
names: 新变量名列表
repeated_vars: 需要修改的变量map
 */
function renameAllVar(ast, names, repeated_vars){
    traverse(ast,{
        VariableDeclarator(path){
            if (repeated_vars.has(path.node.id.name)){// && path.parentPath.isVariableDeclaration({ kind: 'var' })){
                path.scope.rename(path.node.id.name, names.pop());
            }
        }
    })
}


/*
对一个对象的属性进行名字修改, 包括它的引用
可能会出错，当使用 ["a"] 这样的方式时可能不准确.
 */
function renameObjectMember(ast, old_name, new_name){
    traverse(ast, {
        ObjectProperty(path) {
            // 查找名为 myMethod 的属性
            if (path.node.key.name === old_name) {
                // 将属性名替换为 myMethod1
                path.node.key.name = new_name;
            }
        },
        MemberExpression(path) {
            // 查找对 myObject.myMethod 的引用
            if (path.node.property.name === old_name) {
                path.node.property.name = new_name; // 替换为 myMethod1
            }
        },
        StringLiteral(path) {
            // 查找对 myObject["myMethod"] 的引用
            if (path.node.value === 'myMethod') {
                path.node.value = 'myMethod1'; // 替换为 myMethod1
            }
        }
    });

// 生成修改后的代码
    var output = generate(ast).code;
    return output;
}

//代码执行
function evaluateExpression(node) {
    try {
        return eval(generate(node).code);
    } catch (e) {
        return null;
    }
}

function unary_tool(ast){
    traverse(ast, {
        enter(path) {
            // types.isBinaryExpression(path.node)
            if (types.isUnaryExpression(path.node)) {
                const evaluatedValue = evaluateExpression(path.node);
                // console.log(path.node);
                // console.log(generate(path.node).code);
                // console.log(evaluatedValue);
                if (evaluatedValue !== null) {
                    path.replaceWith(types.valueToNode(evaluatedValue));
                }
            }
        }
    });
}

function simplifyConstantExpressions(ast) {
    let modified = true;

    while (modified) {
        modified = false;
        const nodesToCheck = [ast];

        while (nodesToCheck.length > 0) {
            const currentNode = nodesToCheck.pop();

            traverse.cheap(currentNode, node => {
                if (types.isBinaryExpression(node)) {
                    const left = node.left;
                    const right = node.right;

                    if (types.isNumericLiteral(left) && types.isNumericLiteral(right)) {
                        const evaluatedValue = evaluateExpression(node);

                        if (evaluatedValue !== null) {
                            Object.assign(node, types.valueToNode(evaluatedValue));
                            modified = true;
                        }
                    }
                }
                nodesToCheck.push(node);
            });
        }
    }
}



module.exports = {
    getAstByString,
    genCodeByAst,
    unary_tool,
    simplifyConstantExpressions,
    renameAllFuncName,
    renameAllFuncParam,
    renameAllVar,
    renameAllCacheParam,
    renameObjectMember
}